using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using UwinEducation.Application.Common.Interfaces.Orders;
using UwinEducation.Application.Dtos;
using UwinEducation.Application.Dtos.Orders;
using UwinEducation.Domain.Entities;
using UwinEducation.Domain.IRepositories;
using UwinEducation.Infrastructure.Persistence;
using UwinEducation.Infrastructure.Repositories;
using UwinEducation.Shared.Enums;
using UwinEducation.Shared.Exceptions;
using UwinEducation.Shared.Models;
using Microsoft.EntityFrameworkCore;
using UwinEducation.Shared.Services;

namespace UwinEducation.Application.Services.Orders
{
    /// <summary>
    /// 订单详情服务实现
    /// </summary>
    public class OrderDetailService : IOrderDetailService
    {
        private readonly IOrderDetailRepository _orderDetailRepository;
        private readonly IOrderRepository _orderRepository;
        private readonly ITeacherScheduleRepository _teacherScheduleRepository;
        private readonly ITeacherScheduleDetailsRepository _teacherScheduleDetailsRepository;

        private readonly IStudentScheduleDetailsRepository _studentScheduleDetailsRepository;
        private readonly IStudentRepository _studentRepository;
        private readonly ApplicationDbContext _context;
        private readonly IMapper _mapper;
        private readonly ICurrentUserService _currentUserService;

        public OrderDetailService(
            IOrderDetailRepository orderDetailRepository,
            IOrderRepository orderRepository,
            ITeacherScheduleRepository teacherScheduleRepository,
            ITeacherScheduleDetailsRepository teacherScheduleDetailsRepository,
            IStudentScheduleDetailsRepository studentScheduleDetailsRepository,
            IStudentRepository studentRepository,
            IMapper mapper,
            ApplicationDbContext context,
            ICurrentUserService currentUserService
        )
        {
            _orderDetailRepository = orderDetailRepository;
            _orderRepository = orderRepository;
            _teacherScheduleRepository = teacherScheduleRepository;
            _teacherScheduleDetailsRepository = teacherScheduleDetailsRepository;
            _studentScheduleDetailsRepository = studentScheduleDetailsRepository;
            _studentRepository = studentRepository;
            _mapper = mapper;
            _context = context;
            _currentUserService = currentUserService;
        }

        /// <summary>
        /// 获取订单详情
        /// </summary>
        public async Task<OrderDetailDto> GetByIdAsync(Guid id)
        {
            var orderDetail = await _orderDetailRepository.GetByIdAsync(id);
            if (orderDetail == null)
            {
                throw new ArgumentException($"订单详情不存在:{id}");
            }
            return _mapper.Map<OrderDetailDto>(orderDetail);
        }

        /// <summary>
        /// 获取订单的所有详情
        /// </summary>
        public async Task<List<OrderDetailDto>> GetByOrderIdAsync(Guid orderId)
        {
            var orderDetails = await _orderDetailRepository.GetByOrderIdAsync(orderId);
            return _mapper.Map<List<OrderDetailDto>>(orderDetails);
        }

        /// <summary>
        /// 根据教师课表ID获取订单详情
        /// </summary>
        public async Task<List<OrderDetailDto>> GetByTeacherScheduleIdAsync(Guid teacherScheduleId)
        {
            var orderDetails = await _orderDetailRepository.GetByTeacherScheduleIdAsync(
                teacherScheduleId
            );
            return _mapper.Map<List<OrderDetailDto>>(orderDetails);
        }

        /// <summary>
        /// 添加订单详情
        /// </summary>
        public async Task<OrderDetailDto> AddAsync(
            CreateOrderDetailDto createOrderDetailDto,
            Guid orderId
        )
        {
            List<string> businessExceptions = new List<string>();
            // 验证订单是否存在
            await ValidateOrderExistenceAsync(orderId);
            //学生是否存在
            await ValidateStudentExistenceAsync(createOrderDetailDto.StudentId);

            // 验证教师课表是否存在和容量是否足够
            var teacherSchedule = await ValidateTeacherScheduleCapacityAsync(createOrderDetailDto);

            //批量验证课表是否存在
            await ValidateTeacherScheduleDetailsCapacityAsync(createOrderDetailDto);

            //验证教师课表是否废弃
            await ValidateTeacherScheduleIsInvalidAsync(createOrderDetailDto);

            //学生课表时间是否冲突
            await ValidateStudentScheduleTimeConflictAsync(createOrderDetailDto, businessExceptions);

            if (createOrderDetailDto.IsForceCheck)
            {
                if (businessExceptions != null && businessExceptions.Count > 0)
                {
                    throw new BusinessException(businessExceptions, "StudentSchedule");
                }
            }

            // 3. 验证OrderDetail
            var orderDetail =
                await _orderDetailRepository.GetByOrderIdAndStudentIdAndTeacherScheduleIdAsync(
                    orderId,
                    createOrderDetailDto.StudentId,
                    createOrderDetailDto.TeacherScheduleId
                );
            if (orderDetail != null)
            {
                //根据createOrderDetailDto.StudentScheduleDetailsDtos验证学生课程详情是否已存在
                foreach (
                    var studentScheduleDetailDto in createOrderDetailDto.StudentScheduleDetailsDtos
                )
                {
                    var studentScheduleDetail =
                        await _studentScheduleDetailsRepository.GetByOrderDetailIdAndTeacherScheduleIdAsync(
                            orderDetail.Id,
                            studentScheduleDetailDto.TeacherScheduleDetailsId
                        );
                    if (studentScheduleDetail != null)
                    {
                        throw new ArgumentException(
                            "学生课程详情已存在" + studentScheduleDetailDto.TeacherScheduleDetailsId
                        );
                    }
                }

                await _studentScheduleDetailsRepository.AddRangeAsync(
                    createOrderDetailDto
                        .StudentScheduleDetailsDtos.Select(x =>
                            StudentScheduleDetails.Create(
                                orderDetail.Id,
                                x.TeacherScheduleDetailsId,
                                createOrderDetailDto.IsForceCheck,
                                x.CourseType,
                                string.Empty,
                                x.Remarks
                            )
                        )
                        .ToList()
                );

                return _mapper.Map<OrderDetailDto>(orderDetail);
            }
            else
            {
                // 创建订单详情
                orderDetail = OrderDetail.Create(
                    orderId,
                    createOrderDetailDto.TeacherScheduleId,
                    createOrderDetailDto.StudentId,
                    teacherSchedule.UnitPrice,
                    createOrderDetailDto.IsForceCheck
                );

                orderDetail.StudentScheduleDetails = createOrderDetailDto
                    .StudentScheduleDetailsDtos.Select(x =>
                        StudentScheduleDetails.Create(
                            orderDetail.Id,
                            x.TeacherScheduleDetailsId,
                            createOrderDetailDto.IsForceCheck,
                            x.CourseType,
                            string.Empty,
                            x.Remarks
                        )
                    )
                    .ToList();

                // 4. 保存订单详情
                await _orderDetailRepository.AddAsync(orderDetail);
                return _mapper.Map<OrderDetailDto>(orderDetail);
            }
        }

        /// <summary>
        /// 验证学生课表时间冲突
        /// </summary>
        private async Task ValidateStudentScheduleTimeConflictAsync(
            CreateOrderDetailDto createOrderDetailDto,
            List<string> businessExceptions
        )
        {
            //根据IDS批量查询 TeacherScheduleDetails
            var teacherSchedulesDetails = await _teacherScheduleDetailsRepository.GetByIdsAsync(
                createOrderDetailDto.StudentScheduleDetailsDtos.Select(x => x.TeacherScheduleDetailsId).ToList()
            );
            if (teacherSchedulesDetails == null|| teacherSchedulesDetails.Count==0)
                return;
            //根据teacherSchedulesDetails，算出最早的开始时间和最晚的结束时间

            var startTime = teacherSchedulesDetails.Min(x => x.StartTime);
            var endTime = teacherSchedulesDetails.Max(x => x.EndTime);

            //获取学生所有现有课表
            var studentSchedules = await _studentScheduleDetailsRepository.GetByStudentIdAsync(
                createOrderDetailDto.StudentId,
                startTime,
                endTime
            );


            // 时间段冲突的条件：
            // 1. 新开始时间在现有时间段内
            // 2. 新结束时间在现有时间段内
            // 3. 新时间段完全包含现有时间段
            foreach (var schedule in studentSchedules)
            {
                if (schedule.TeacherScheduleDetails.Status != ScheduleStatus.Normal)
                    continue;
                var hasConflict = teacherSchedulesDetails
                .Where(x => x.Status == ScheduleStatus.Normal)
                .Any(x =>
                    (schedule.TeacherScheduleDetails.StartTime >= x.StartTime && schedule.TeacherScheduleDetails.StartTime < x.EndTime) ||
                    (schedule.TeacherScheduleDetails.EndTime > x.StartTime && schedule.TeacherScheduleDetails.EndTime <= x.EndTime) ||
                    (schedule.TeacherScheduleDetails.StartTime < x.StartTime && schedule.TeacherScheduleDetails.EndTime > x.EndTime)
                );
                    //    .Any(x =>
                    //    (schedule.StartTime > x.StartTime && schedule.StartTime < x.EndTime)
                    //    || (schedule.EndTime > x.StartTime && schedule.EndTime < x.EndTime)
                    //    || (schedule.StartTime < x.StartTime && schedule.EndTime > x.EndTime)
                    //);

                if (hasConflict)
                {
                    businessExceptions.Add(
                        $"时间冲突: {schedule.TeacherScheduleDetails.StartTime:yyyy-MM-dd HH:mm} - {schedule.TeacherScheduleDetails.EndTime:yyyy-MM-dd HH:mm} 与 {schedule.TeacherScheduleDetails.TeacherSchedule.Course.Name} 时间重叠"
                    );
                }
            }

        }

        /// <summary>
        /// 验证教师课表是否废弃
        /// </summary>
        private async Task ValidateTeacherScheduleIsInvalidAsync(CreateOrderDetailDto detailDto)
        {
            var teacherSchedules = await _teacherScheduleRepository.GetByGroupIdAsync(
                detailDto.TeacherScheduleId
            );
            //提示具体哪一天的课表已废弃
            var abandonedTeacherScheduleDetails = teacherSchedules
                .SelectMany(x => x.TeacherScheduleDetails)
                .Where(y => y.Status == ScheduleStatus.Abandoned)
                .ToList();
            if (abandonedTeacherScheduleDetails.Count > 0)
            {
                throw new ArgumentException(
                    $"教师课表已废弃: {abandonedTeacherScheduleDetails.Select(x => x.StartTime.ToString("yyyy-MM-dd")).Aggregate((x, y) => $"{x}, {y}")}"
                );
            }
        }

        private async Task ValidateTeacherScheduleDetailsCapacityAsync(
            CreateOrderDetailDto createOrderDetailDto
        )
        {
            //批量验证学生课表详情是否已经存在，如果存在则抛出异常
            foreach (
                var studentScheduleDetailDto in createOrderDetailDto.StudentScheduleDetailsDtos
            )
            {
                var studentScheduleDetail =
                    await _studentScheduleDetailsRepository.GetByStudentIdAndTeacherScheduleDetailsIdAsync(
                        createOrderDetailDto.StudentId,
                        studentScheduleDetailDto.TeacherScheduleDetailsId
                    );
                if (studentScheduleDetail != null)
                {
                    throw new ArgumentException(
                        "学生课表详情已存在" + studentScheduleDetailDto.TeacherScheduleDetailsId
                    );
                }
            }
        }

        private async Task ValidateOrderExistenceAsync(Guid orderId)
        {
            var order = await _orderRepository.GetByIdAsync(orderId);
            if (order == null)
            {
                throw new ArgumentException("订单不存在" + orderId);
            }
        }

        private async Task ValidateStudentExistenceAsync(Guid studentId)
        {
            var student = await _studentRepository.GetByIdAsync(studentId);
            if (student == null)
            {
                throw new ArgumentException($"学生不存在: {studentId}");
            }
        }

        private async Task<TeacherSchedule> ValidateTeacherScheduleCapacityAsync(CreateOrderDetailDto dto)
        {
            var teacherSchedule = await _teacherScheduleRepository.GetByIdAsync(
                dto.TeacherScheduleId
            );
            //教师课表组容量是否足够
            var usedCapacity =
                await _studentScheduleDetailsRepository.GetUsedCapacityByTeacherScheduleIdAsync(
                    dto.TeacherScheduleId,
                    dto.StudentId
                );

            if (teacherSchedule != null && usedCapacity >= teacherSchedule.Capacity)
            {
                throw new ArgumentException($"教师课表容量不足: {teacherSchedule.Course.Name}, 已选{usedCapacity}人，容量{teacherSchedule.Capacity}人");
            }
            return teacherSchedule;
        }

        /// <summary>
        /// 更新订单详情
        /// </summary>
        public async Task<OrderDetailDto> UpdateAsync(UpdateOrderDetailDto updateOrderDetailDto)
        {
            // 1. 获取订单详情
            var orderDetail = await _orderDetailRepository.GetByIdAsync(updateOrderDetailDto.Id);
            if (orderDetail == null)
            {
                throw new ArgumentException("订单详情不存在" + updateOrderDetailDto.Id);
            }

            // 2. 更新订单详情
            orderDetail.UnitPrice = updateOrderDetailDto.UnitPrice;

            // 3. 保存更新
            await _orderDetailRepository.UpdateAsync(orderDetail);

            return _mapper.Map<OrderDetailDto>(orderDetail);
        }

        /// <summary>
        /// 删除订单详情
        /// </summary>
        public async Task DeleteAsync(Guid id)
        {
            // 先检查订单详情是否存在，但只获取ID信息，不加载关联对象
            var orderDetail = await _orderDetailRepository.GetByIdAsync(id);
            if (orderDetail == null)
            {
                throw new ArgumentException("订单详情不存在" + id);
            }
            
            // 添加事务
            using (var transaction = await _context.Database.BeginTransactionAsync())
            {
                try
                {
                    // 清空当前上下文跟踪的所有实体
                    _context.ChangeTracker.Clear();
                    
                    // 获取学生课表详情ID列表而不是完整实体
                    var studentScheduleDetails = 
                        await _studentScheduleDetailsRepository.GetByOrderDetailIdAsync(id);
                        
                    if (studentScheduleDetails != null && studentScheduleDetails.Count > 0)
                    {
                        // 获取ID列表并在数据库级别直接删除，避免实体跟踪
                        var detailIds = studentScheduleDetails.Select(d => d.Id).ToList();
                        
                        // 直接在数据库级别删除这些记录，批量逻辑删除
                        await _context.Database.ExecuteSqlRawAsync(
                            "UPDATE student_schedules_details SET IsDeleted = 1,UpdatedAt = NOW(),UpdatedBy = {0} WHERE OrderDetailId = {1}",
                            _currentUserService.UserId ?? Guid.Empty,
                            id);
                    }
                    
                    // 直接在数据库级别删除订单详情，逻辑删除
                    await _context.Database.ExecuteSqlRawAsync(
                        "UPDATE order_details SET IsDeleted = 1,UpdatedAt = NOW(),UpdatedBy = {0} WHERE Id = {1}", 
                        _currentUserService.UserId ?? Guid.Empty,id);

                    if(orderDetail.TeacherScheduleId!=null&& orderDetail.TeacherSchedule.Capacity==1)
                    {
                        // 获取教师课表详情
                        var teacherScheduleDetails =await _teacherScheduleDetailsRepository.GetByTeacherScheduleIdAsync(orderDetail.TeacherScheduleId);

                        if (teacherScheduleDetails != null && teacherScheduleDetails.Count > 0)
                        {
                            // 获取ID列表并在数据库级别直接删除
                            var detailIds = teacherScheduleDetails.Select(d => d.Id).ToList();
                            // 直接在数据库级别删除这些记录

                            await _context.Database.ExecuteSqlRawAsync(
                                "UPDATE teacher_schedules_details SET IsDeleted = 1,UpdatedAt = NOW(),UpdatedBy = {0} WHERE TeacherScheduleId = {1}",
                                _currentUserService.UserId ?? Guid.Empty,
                                orderDetail.TeacherScheduleId);
                        }
                        // 直接在数据库级别删除教师课表
                        await _context.Database.ExecuteSqlRawAsync(
                            "UPDATE teacher_schedules SET IsDeleted = 1,UpdatedAt = NOW(),UpdatedBy = {0} WHERE Id = {1}",
                            _currentUserService.UserId ?? Guid.Empty,
                            orderDetail.TeacherScheduleId);
                    }

                    await transaction.CommitAsync();
                }
                catch (Exception ex)
                {
                    await transaction.RollbackAsync();
                    throw new Exception("删除订单详情失败", ex);
                }
            }
        }

        /// <summary>
        /// 批量删除订单详情
        /// </summary>
        public async Task DeleteRangeAsync(List<Guid> ids)
        {
            // 使用事务确保所有删除操作作为一个整体
            using (var transaction = await _context.Database.BeginTransactionAsync())
            {
                try
                {
                    // 清空当前上下文跟踪的所有实体
                    _context.ChangeTracker.Clear();
                    
                    foreach (var id in ids)
                    {
                        // 检查订单详情是否存在
                        var orderDetail = await _orderDetailRepository.GetByIdAsync(id);
                        if (orderDetail == null) continue;
                        
                        // 获取学生课表详情
                        var studentScheduleDetails = 
                            await _studentScheduleDetailsRepository.GetByOrderDetailIdAsync(id);
                        
                        if (studentScheduleDetails != null && studentScheduleDetails.Count > 0)
                        {
                            // 获取ID列表并在数据库级别直接删除
                            var detailIds = studentScheduleDetails.Select(d => d.Id).ToList();
                            
                            // 直接在数据库级别删除这些记录
                            await _context.Database.ExecuteSqlRawAsync(
                                "UPDATE student_schedules_details SET IsDeleted = 1 WHERE Id IN ({0})", 
                                string.Join(",", detailIds));
                        }
                        
                        // 直接在数据库级别删除订单详情
                        await _context.Database.ExecuteSqlRawAsync(
                            "UPDATE order_details SET IsDeleted = 1 WHERE Id = {0}", 
                            id);
                    }
                    
                    await transaction.CommitAsync();
                }
                catch (Exception ex)
                {
                    await transaction.RollbackAsync();
                    throw new Exception("批量删除订单详情失败", ex);
                }
            }
        }

        /// <summary>
        /// 分页查询订单详情
        /// </summary>
        public async Task<PagedResult<OrderDetailDto>> GetPagedAsync(OrderDetailPageRequest request)
        {
            // 调用仓储层的分页查询方法
            var result = await _orderDetailRepository.GetPagedAsync(request);

            // 转换结果为DTO
            var dtos = _mapper.Map<List<OrderDetailDto>>(result.Items);

            return new PagedResult<OrderDetailDto> { Items = dtos, Total = result.Total };
        }
    }
}
